package com.mouxidea;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;

public class RecordMonitor implements Runnable{
	
	private Config config = null;
	private DBManager dbManager = null;
	private File outputFolder = null;
	
	public RecordMonitor(){
		this.config = Config.getInstance();
		this.dbManager = new DBManager();
		
		this.outputFolder = new File(this.config.getOutputFolderName());
		if (!this.outputFolder.isDirectory())
		{
			this.outputFolder.mkdirs();
		}
	}
	
	public void run(){
		List<String> dsiKeyIdList = dbManager.getAllDsiKeyId();

		for (String id : dsiKeyIdList)
		{
			processComparison(id);
			processUtilization(id);
		}
		
	}
	
	private void processComparison(String id){
		Config config = Config.getInstance();
		ComparisonRule comparisonRule = config.getComparisonMap().get(id);
		if (comparisonRule != null)
		{
			String comparisonType = comparisonRule.getColumn();
			if (comparisonType != null)
			{
				if ((!comparisonType.equals(Config.AVG_IN_UTIL_F)) && 
					(!comparisonType.equals(Config.AVG_OUT_UTIL_F)) && 
					(!comparisonType.equals(Config.AVG_UTIL_H)) &&
					(!comparisonType.equals(Config.MAX_IN_UTIL_F)) &&
					(!comparisonType.equals(Config.MAX_OUT_UTIL_F)) &&
					(!comparisonType.equals(Config.MAX_UTIL_H)))
				{
					return;
				}
				//get latest 6 records from DB
				//System.out.println("Getting Latest 6 records");
				List<Record> recordList = dbManager.getLatestRecords(id, 6);
				//System.out.println("Got Latest 6 records");
				//System.out.println("Total received records: " + recordList.size());
				//System.out.println();
	
				//System.out.println("Getting Last Week Records");
				List<Record> record1WkList = dbManager.get1WkOldRecords(id);
				//System.out.println("Getting Last Week Records");
				//System.out.println("Total received records: " + record1WkList.size());
				//System.out.println();
				Record record1Wk = null;
				if (record1WkList.size() > 0)
				{
					record1Wk = record1WkList.get(0);
				}
	
				//System.out.println("Getting Last Month Records");
				List<Record> record1MthList = dbManager.get1MthOldRecords(id);
				//System.out.println("Got Last Month Records");
				//System.out.println("Total received records: " + record1MthList.size());
				//System.out.println();
				Record record1Mth = null;
				if (record1MthList.size() > 0)
				{
					record1Mth = record1MthList.get(0);
				}
				
				//calculate the average values for comparison
				Record subjectRecord = recordList.get(0);
	
				//check whether the difference is too large
				boolean overThresholdLatest = false;
				boolean overThresholdLastWk = false;
				boolean overThresholdLastMth = false;
				double threshold = comparisonRule.getValue() / 100;
				String strOutput = "";
				int hitCount = 0;
				strOutput += "Compare column: " + comparisonType;
				if (recordList.size() < 2){
					strOutput += "Comparing latest 5 records\r\n";
					for (int i=1; i<recordList.size(); i++){
						Record record = recordList.get(i);
						double compareValue = Math.abs((subjectRecord.getValueByKey(comparisonType) - record.getValueByKey(comparisonType)) / record.getValueByKey(comparisonType));
						
						//if (record.getValueByKey(comparisonType) < subjectRecord.getValueByKey(comparisonType) * threshold || 
						//	record.getValueByKey(comparisonType) > subjectRecord.getValueByKey(comparisonType) * threshold)
						if (compareValue > threshold)
						{
							hitCount++;
							strOutput += "No. " + i + ": hit - " + hitCount + "\r\n";
							strOutput += "latest value: " + subjectRecord.getValueByKey(comparisonType) + "\r\n"; 
							strOutput += "compare value: " + record.getValueByKey(comparisonType) + "\r\n"; 
						}
						else
						{
							strOutput += "No. " + i + ": did not hit \r\n";
							strOutput += "latest value: " + subjectRecord.getValueByKey(comparisonType) + "\r\n"; 
							strOutput += "compare value: " + record.getValueByKey(comparisonType) + "\r\n";
							strOutput += "compare percentage: " + compareValue + "\r\n";
							strOutput += "threshold: " + threshold + "\r\n";
						}
						if (hitCount >= 3)
						{
							overThresholdLatest = true;
							strOutput += "Hit " + hitCount + " and output as Warning\r\n";
							break;
						}
					}
				}
				strOutput += "Comparing last week record\r\n";
				if (record1Wk != null)
				{
					double compareValue = Math.abs((subjectRecord.getValueByKey(comparisonType) - record1Wk.getValueByKey(comparisonType)) / record1Wk.getValueByKey(comparisonType));
					//overThresholdLastWk = overThresholdLastWk || (record1Wk.getValueByKey(comparisonType) < subjectRecord.getValueByKey(comparisonType) * threshold || 
					//											  record1Wk.getValueByKey(comparisonType) > subjectRecord.getValueByKey(comparisonType) * threshold);
					overThresholdLastWk = (compareValue > threshold);
					if (overThresholdLastWk)
					{
						strOutput = "Hit last week record warning: \r\n";
						strOutput += "latest value: " + subjectRecord.getValueByKey(comparisonType) + "\r\n"; 
						strOutput += "compare value: " + record1Wk.getValueByKey(comparisonType) + "\r\n"; 
					}
					else
					{
						strOutput += "Did not hit last week record warning: \r\n";
						strOutput += "latest value: " + subjectRecord.getValueByKey(comparisonType) + "\r\n"; 
						strOutput += "compare value: " + record1Wk.getValueByKey(comparisonType) + "\r\n";
						strOutput += "compare percentage: " + compareValue + "\r\n";
						strOutput += "threshold: " + threshold + "\r\n";
					}
				}
				strOutput += "Comparing last month record\r\n";
				if (record1Mth != null)
				{
					double compareValue = Math.abs((subjectRecord.getValueByKey(comparisonType) - record1Mth.getValueByKey(comparisonType)) / record1Mth.getValueByKey(comparisonType));
					//overThresholdLastMth = overThresholdLastMth || (record1Mth.getValueByKey(comparisonType) < subjectRecord.getValueByKey(comparisonType) * threshold || 
					//												record1Mth.getValueByKey(comparisonType) > subjectRecord.getValueByKey(comparisonType) * threshold);
					overThresholdLastMth = (compareValue > threshold);
					if (overThresholdLastMth)
					{
						strOutput = "Hit last month record warning: \r\n";
						strOutput += "latest value: " + subjectRecord.getValueByKey(comparisonType) + "\r\n"; 
						strOutput += "compare value: " + record1Mth.getValueByKey(comparisonType) + "\r\n"; 
					}
					else
					{
						strOutput += "Did not hit last month record warning: \r\n";
						strOutput += "latest value: " + subjectRecord.getValueByKey(comparisonType) + "\r\n"; 
						strOutput += "compare value: " + record1Mth.getValueByKey(comparisonType) + "\r\n";
						strOutput += "compare percentage: " + compareValue + "\r\n";
						strOutput += "threshold: " + threshold + "\r\n";
					}
				}


				
				if (overThresholdLatest || overThresholdLastWk || overThresholdLastMth)
				{
					int alarmLevel = 0;//1=Critical, 2=Major, 3=Minor
					if (overThresholdLatest){
						alarmLevel = 1;
					}
					else if (overThresholdLastWk || overThresholdLastMth){
						alarmLevel = 2;
					} 
					//Send alert command
					MailSender.sendAlertEmail(strOutput, alarmLevel);
					SnmpTrapSender.sendTrap();
				}
				
				writeToFile(id, strOutput+"\r\n\r\n\r\n");
			}
			else
			{
				System.out.println("Cannot found the comparisonType with id: " + id);
			}
		
		}
	}
	
	private void processUtilization(String id){
		Config config = Config.getInstance();
		UtilizationRule utilizationRule = config.getUtilizationMap().get(id);
		if (utilizationRule != null)
		{
			String comparisonType = utilizationRule.getColumn();
			if (comparisonType != null)
			{
				if ((!comparisonType.equals(Config.AVG_IN_UTIL_F)) && 
					(!comparisonType.equals(Config.AVG_OUT_UTIL_F)) && 
					(!comparisonType.equals(Config.AVG_UTIL_H)) &&
					(!comparisonType.equals(Config.MAX_IN_UTIL_F)) &&
					(!comparisonType.equals(Config.MAX_OUT_UTIL_F)) &&
					(!comparisonType.equals(Config.MAX_UTIL_H)))
				{
					return;
				}
				//get latest 1 records from DB
				//System.out.println("Getting Latest 1 records");
				List<Record> recordList = dbManager.getLatestRecords(id, 1);
				//System.out.println("Got Latest 1 records");
				//System.out.println("Total received records: " + recordList.size());
				//System.out.println();
				
				Record subjectRecord = recordList.get(0);
				double threshold = utilizationRule.getValue() / 100;
				Calendar fromTime = Calendar.getInstance();
				Calendar toTime = Calendar.getInstance();
				int noOfSample = utilizationRule.getNoOfSample();
				int interval = utilizationRule.getSamplingInterval();
				String strOutput = "";
				int hitCount = 0; 
				strOutput += "Compare column: " + comparisonType;
				strOutput += "Comparing "+noOfSample+" x "+interval+" min records\r\n";
				for (int i=0; i<noOfSample; i++){
					//for each iteration, move time to <interval> min earlier
					fromTime.add(Calendar.MINUTE, (i*(-interval)) - interval);//always <interval> min before toTime
					toTime.add(Calendar.MINUTE, (i*(-interval)));
					String fromTimeStr = getDateStringForSql(fromTime);
					String toTimeStr = getDateStringForSql(toTime);
					List<Record> list = dbManager.getCustomizedRecords(id, fromTimeStr, toTimeStr); 
					if (list==null || list.size()==0){
						hitCount++;
					}
					else {
						Record record = list.get(0);
						double compareValue = Math.abs((subjectRecord.getValueByKey(comparisonType) - record.getValueByKey(comparisonType)) / record.getValueByKey(comparisonType));
						
						if (compareValue > threshold)
						{
							hitCount++;
							strOutput += "No. " + i + ": hit - " + hitCount + "\r\n";
							strOutput += "latest value: " + subjectRecord.getValueByKey(comparisonType) + "\r\n"; 
							strOutput += "compare value: " + record.getValueByKey(comparisonType) + "\r\n";
						}
						else
						{
							strOutput += "No. " + i + ": did not hit \r\n";
							strOutput += "latest value: " + subjectRecord.getValueByKey(comparisonType) + "\r\n"; 
							strOutput += "compare value: " + record.getValueByKey(comparisonType) + "\r\n";
							strOutput += "compare percentage: " + compareValue + "\r\n";
							strOutput += "threshold: " + threshold + "\r\n";
						}
					}
				}
				
				if (hitCount == noOfSample){
					MailSender.sendAlertEmail(strOutput, utilizationRule.getAlarmLevel());
					SnmpTrapSender.sendTrap();
				}
	
				writeToFile(id, strOutput+"\r\n\r\n\r\n");
				
			}
			else
			{
				System.out.println("Cannot found the comparisonType with id: " + id);
			}
		
		}
	}
	
	private String getDateStringForSql(Calendar time){
		String year = String.valueOf(time.get(Calendar.YEAR));
		String month = String.valueOf(time.get(Calendar.MONTH)+1);
		String day = String.valueOf(time.get(Calendar.DAY_OF_MONTH));
		String hour = String.valueOf(time.get(Calendar.HOUR_OF_DAY));
		String minute = String.valueOf(time.get(Calendar.MINUTE));
		String second = String.valueOf(time.get(Calendar.SECOND));
		
		if (month.length()<2){
			month = "0" + month;
		}
		if (day.length()<2){
			day = "0" + day;
		}
		if (hour.length()<2){
			hour = "0" + hour;
		}
		if (minute.length()<2){
			minute = "0" + minute;
		}
		if (second.length()<2){
			second = "0" + second;
		}
		
		return "to_date('"+year+"-"+month+"-"+day+" "+hour+":"+minute+":"+second+"', 'YYYY-MM-DD HH24:MI:SS')";
	}
	
	private void writeToFile(String id, String content){
		File outputFile = new File(outputFolder.getAbsolutePath()+File.separator+id+".txt");
		System.out.println("Writing file to log file: " + outputFile.getAbsolutePath());
		
		if (!outputFile.isFile()){
			try {
				outputFile.createNewFile();

			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		FileOutputStream fout = null;
		try{
			fout = new FileOutputStream(outputFile, true);

			//write one line to file
			String str = content+"\r\n\r\n\r\n";
			fout.write(str.getBytes());
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			try{fout.close();}catch(Exception ignored){}
		}
	}
	

	public static void main(String[] args){
		RecordMonitor recordMonitor = new RecordMonitor();
		recordMonitor.run();
	}
}
